package machiavelli;

import java.util.*;

public class Solver {
	protected Mazzo mazzo;
	protected ArrayList<Carta> mano;
	
	protected ArrayList<ArrayList<Carta>> soluzione;
	protected long numeroManiOsservate;
	
	protected ArrayList<Carta> manoSoluzione;
	
	public Solver(){
		mazzo = new Mazzo();
		soluzione = new ArrayList<ArrayList<Carta>>();
		mano = new ArrayList<Carta>();
		manoSoluzione = new ArrayList<Carta>();
	}
	
	public void aggiungiCartaMano(Carta c){
		mano.add(c);
	}
	public void rimuoviCartaMano(Carta c){
		mano.remove(c);
	}
	
	
	public void aggiungiCartaMazzo(Carta c){
		mazzo.aggiungiCarta(c);
	}
	public void rimuoviCartaMazzo(Carta c){
		mazzo.rimuoviCarta(c);
	}
	
	public ArrayList<ArrayList<Carta>> getSoluzione() {
		return soluzione;
	}

	public void setSoluzione(ArrayList<ArrayList<Carta>> soluzione) {
		this.soluzione = soluzione;
	}
	
	public long getNumeroManiOsservate() {
		return numeroManiOsservate;
	}

		
	public void printMazzo(){
		System.out.print("CARTE MAZZO");
		System.out.print("   ");
		for (int i=0; i<Mazzo.SEMI; i++)
			System.out.print(Mazzo.getSeme(i)+" ");
		System.out.println();
		for (int i=1; i<14; i++)
		{	System.out.print(Mazzo.getValore(i)+" ");
			if (i!=10) System.out.print(" ");
			for (int seme = 0; seme<4; seme++)
				System.out.print(mazzo.getCarta(seme, i)+" ");
			System.out.println();
		}
	}
	
	public void printMano(){
		System.out.println("CARTE MANO");
		for (int i=0; i<mano.size(); i++)
			System.out.print(mano.get(i)+", ");
		System.out.println();
	}
	
	public void printSolution(){
		System.out.println("CARTE DA USARE");
		for (int i=0; i<manoSoluzione.size(); i++)
			System.out.print(manoSoluzione.get(i)+", ");
		System.out.println();
		System.out.println("SOLUZIONE:");
		for (int i=0; i<soluzione.size(); i++)
		{	for (int j=0; j<soluzione.get(i).size(); j++)
				System.out.print(soluzione.get(i).get(j)+", ");
			System.out.println();
		}
	}
	
	public static Carta ottieniCarta(String carta){
		try{
			int s = Mazzo.getSeme(carta.charAt(0)+"");
			int v = Mazzo.getValore(carta.substring(1));
			if (s==-1 || v==-1) {
				if (carta.length()==3)
				{	s = Mazzo.getSeme(carta.substring(2));
					v = Mazzo.getValore(carta.substring(0, 2));
				}else
				{	s = Mazzo.getSeme(carta.substring(1));
					v = Mazzo.getValore(carta.substring(0, 1));
				}
				if (s==-1 || v==-1) return null;
			}
			if (s>=0 && s<Mazzo.SEMI && v>=1 && v<Mazzo.DIM)
				return new Carta(s,v);
		} catch (Exception e){}
		return null;
	}
	
	
	
	public Mazzo getMazzo() {
		return mazzo;
	}

	public void setMazzo(Mazzo mazzo) {
		this.mazzo = mazzo;
	}

	public ArrayList<Carta> getMano() {
		return mano;
	}

	public void setMano(ArrayList<Carta> mano) {
		this.mano = mano;
	}
	
	public boolean genera(int numeroCombinazioni){
		numeroManiOsservate = 0;
		IteratoreElementiMano it = new IteratoreElementiMano(numeroCombinazioni);
		it.getMano().addAll(mano);
		it.init();
		System.out.println("K: "+it.getK());
		while (true)
		{	ArrayList<Carta> combinazione = it.next();
			if (combinazione == null) return false;
			numeroManiOsservate++;
			//per ogni mano esegue la ricerca
			soluzione = new ArrayList<ArrayList<Carta>>();
			for (int i=0; i<combinazione.size(); i++)
				mazzo.aggiungiCarta(combinazione.get(i));
			boolean funziona = genera(new Carta(0,1), soluzione);
			for (int i=0; i<combinazione.size(); i++)
				mazzo.rimuoviCarta(combinazione.get(i));
			if (funziona){
				manoSoluzione = combinazione;
				return true;
			}	
		}
	}
	
	protected boolean genera(Carta c, ArrayList<ArrayList<Carta>> soluzione){
		//mazzo vuoto, ho finito!
		if (mazzo.isEmpty()) return true;
		//preleva prossima carta
		Carta next = mazzo.getNextNonNull(c);
		//controllo in orizzontale
		if (mazzo.canFillRow(next.getValore())){
			//genero tutti i tris/quatris possibili
			ArrayList<ArrayList<Carta>> trisPossibili = mazzo.generaTris(next);
			Iterator<ArrayList<Carta>> s = trisPossibili.iterator();
			while (s.hasNext()){
				//per ogni gruppo, controllo se porta ad una soluzione
				ArrayList<Carta> tris = s.next();
				for (int i=0; i<tris.size(); i++)
					mazzo.rimuoviCarta(tris.get(i));
				boolean funziona = genera(next, soluzione);
				for (int i=0; i<tris.size(); i++)
					mazzo.aggiungiCarta(tris.get(i));
				//ha funzionato, aggiorno ed esco
				if (funziona){
					soluzione.add(tris);
					return true;
				}
			}
		}
		//controllo in verticale
		if (mazzo.canFillCol(next)){
			//genero tutte le scale possibili
			ArrayList<ArrayList<Carta>> scalePossibili = mazzo.generaScale(next);
			Iterator<ArrayList<Carta>> s = scalePossibili.iterator();
			while (s.hasNext()){
				//per ogni gruppo, controllo se porta ad una soluzione
				ArrayList<Carta> scala = s.next();
					
				for (int i=0; i<scala.size(); i++)
					mazzo.rimuoviCarta(scala.get(i));
				boolean funziona = genera(next, soluzione);
				for (int i=0; i<scala.size(); i++)
					mazzo.aggiungiCarta(scala.get(i));
				//ha funzionato, aggiorno ed esco
				if (funziona){
					soluzione.add(scala);
					return true;
				}
			}
		}
		return false;
	}

}
